package com.android.stockme.backend.portfolio;


import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;

import android.util.Log;

import com.android.stockme.backend.configuration.IConfigurationChangedListener;
import com.android.stockme.backend.configuration.IConfigurationManager;
import com.android.stockme.backend.util.Tupple;



public class StockPortfolio implements IStockProtfolio {

	/**
	 * @uml.property  name="stocks"
	 * @uml.associationEnd  inverse="stockPortfolio:android.stocktme.StockPortfolio.Stock" qualifier="symbol:java.lang.String android.stocktme.StockPortfolio.Stock"
	 */
	private Map<String, Stock> stocksMap = null;
	private IConfigurationManager configurationManager = null;
	private Collection<IStockPortfolioUpdatedListener> listeners = null;

	
	public StockPortfolio()
	{
		
		this.stocksMap = new HashMap<String, Stock>();
		this.listeners = new HashSet<IStockPortfolioUpdatedListener>();

	}
	
	private class Stock implements IStockData, Cloneable
	{
	
		public Stock(String symbol, float value, float relativeChange, boolean isExists) 
		{
			this.symbol = symbol;
			this.value = value;
			this.relativeChange = relativeChange;
			this.isExists = isExists;
		}
	
		@Override
		public Stock clone() throws CloneNotSupportedException {
			
			return new Stock(this.symbol, this.value, this.relativeChange, this.isExists);
		}

		/**
		 * @uml.property  name="symbol"
		 */
		private String symbol = "";
		
		/**
		 * @uml.property  name="value"
		 */
		private float value;

		/**
		 * @uml.property  name="relativeChange"
		 */
		private float relativeChange;
		
		private boolean isExists = true;
		
		/**
		 * Getter of the property <tt>symbol</tt>
		 * @return  Returns the symbol.
		 * @uml.property  name="symbol"
		 */
		public String getSymbol() {
			return this.symbol;
		}

		/**
		 * Setter of the property <tt>symbol</tt>
		 * @param symbol  The symbol to set.
		 * @uml.property  name="symbol"
		 */
		public void setSymbol(String symbol) {
			
			this.symbol = symbol;
			
		}


		/**
		 * Getter of the property <tt>value</tt>
		 * @return  Returns the value.
		 * @uml.property  name="value"
		 */
		public float getValue() {
			
			return this.value;
			
		}

		/**
		 * Setter of the property <tt>value</tt>
		 * @param value  The value to set.
		 * @uml.property  name="value"
		 */
		public void setValue(float value) {
			
			this.value = value;
			
		}



		/**
		 * Getter of the property <tt>relativeChange</tt>
		 * @return  Returns the relativeChange.
		 * @uml.property  name="relativeChange"
		 */
		public float getRelativeChange() {
			
			return this.relativeChange;
			
		}

		/**
		 * Setter of the property <tt>relativeChange</tt>
		 * @param relativeChange  The relativeChange to set.
		 * @uml.property  name="relativeChange"
		 */
		public void setRelativeChange(float relativeChange) {
			
			this.relativeChange = relativeChange;
			
		}
		
		public void setValuAndRelativeChange(float value ,float relativeChange) {
			
			this.value = value;
			this.relativeChange = relativeChange;
			
		}

		public boolean isExists() {
			return this.isExists;
		}

		public void setExists(boolean isExists) {
			this.isExists = isExists;
		}
	}//Stock Class

	public StockPortfolio(IConfigurationManager configurationManager) {
		this.configurationManager = configurationManager;
		this.stocksMap = new HashMap<String, Stock>();
		this.listeners = new HashSet<IStockPortfolioUpdatedListener>();
		
		for (String s : this.configurationManager.getStockSymbols())
			this.addStock(s);

		this.configurationManager.registerStockAddedListener(new IConfigurationChangedListener() {
			public void notifyConfigurationChanged(Object arg) {
				
				addStock((String)arg);
				postStockPortfolioUpdatedEvent();
				
			}
		});
		

		this.configurationManager.registerStockRemovedListener(new IConfigurationChangedListener() {
			public void notifyConfigurationChanged(Object arg) {
				
				stocksMap.remove((String)arg);
				postStockPortfolioUpdatedEvent();
				
			}
		});
		
	}//StockPortfolio
	
	
	public float getStockRelativeChange(String symbol) {
		
		if (this.stocksMap.containsKey(symbol))
		{
			return this.stocksMap.get(symbol).getRelativeChange();
		}
		return 0;
		
	}

	public float getStockValue(String symbol) {
		
		if (this.stocksMap.containsKey(symbol))
		{
			return this.stocksMap.get(symbol).getValue();
		}
		return 0;
		
	}
	

	public void updatePortfolio(Map<String, Tupple<Float, Float>> data) {

		if (data != null)
		{
			for( Entry<String, Tupple<Float, Float>> stock : data.entrySet() )
			{
				if (this.stocksMap.containsKey(stock.getKey()))
				{
					Tupple<Float, Float> valueAndChange = stock.getValue();
					
					Stock s = this.stocksMap.get(stock.getKey());
					
					if (valueAndChange.getT1() == null && valueAndChange.getT2() == null) {
						s.setExists(false);
						s.setValuAndRelativeChange(0, 0);
					}
					else
						s.setValuAndRelativeChange(valueAndChange.getT1(),valueAndChange.getT2());
				}
				
			}//for			
		}
		
		this.postStockPortfolioUpdatedEvent();//post event
		
	}//updatePortfolio
	
	
	
	public void addStock(String symbol)
	{
		if (!stocksMap.containsKey(symbol))
		{
			
			this.stocksMap.put(symbol, new Stock(symbol, 0 , 0, true));
		}
		
	}//addStock
	
	
	public void updateStockData(String symbol, Tupple<Float, Float> valueAndChange) {

		if (this.stocksMap.containsKey(symbol))
		{
			this.stocksMap.get(symbol).setValuAndRelativeChange(valueAndChange.getT1(),valueAndChange.getT2());
		}
			
	
	}//updateStockData

	
	public void updateStockData(String symbol, Float value , Float change) {

		if (this.stocksMap.containsKey(symbol))
		{
			this.stocksMap.get(symbol).setValuAndRelativeChange(value,change);
		}
			
	}//updateStockData
	
	
	
	public void registerStockPortfolioUpdatedListener(IStockPortfolioUpdatedListener listener) {
		
		if (listener != null)
			this.listeners.add(listener);
		
	}

	
	public void unregisterStockPortfolioUpdatedListener(IStockPortfolioUpdatedListener listener) {
		
		if (listener != null)
			this.listeners.remove(listener);
		
	}

	
	public Runnable getProtfolioUpdateRunnable() {
		// TODO Auto-generated method stub
		return null;
		
	}
	
	
	protected void postStockPortfolioUpdatedEvent() {
		
		for (IStockPortfolioUpdatedListener listener : this.listeners)
			listener.notifyStockPortfolioUpdated(null);
		
	}

	public int getPortfolioSize() {
		
		return this.stocksMap.values().size();
		
	}

	public void addStocks(Collection<String> symbols) {
		
		for (String symbol : symbols) {
			if (!stocksMap.containsKey(symbol)) {
				Stock stock = new Stock(symbol, 0 , 0, true);
				this.stocksMap.put(symbol, stock);
			}
		}
		this.postStockPortfolioUpdatedEvent();//post event
		
	}

	
	public IStockData getStockData(String symbol) {
		
		if (this.stocksMap.containsKey(symbol))
			try {
				return this.stocksMap.get(symbol).clone();
			} catch (CloneNotSupportedException e) {
				Log.e("StockMe", e.getMessage());
			}
		return null;
		
	}

	
	public ArrayList<IStockData> getStocks() {
		
		ArrayList<IStockData> stocks = new ArrayList<IStockData>();
		
		for (Stock s : this.stocksMap.values())
			try {
				stocks.add(s.clone());
			} catch (CloneNotSupportedException e) {
				Log.e("StockMe", e.getMessage());
			}
		
		return stocks;
		
	}
	
	public void setZerous() {
		
		for (Stock stock : this.stocksMap.values())
		{
			stock.setValue(0);
			stock.setRelativeChange(0);
		}
		
		
	}//setZerous
	
	
}//StockPortfolio class